﻿''' <summary>
''' Executes scripts.
''' </summary>
''' <remarks></remarks>
''' <editHistory></editHistory>
Public Class ScriptExecutor
    Implements IDisposable

    Private _scriptProject As ScriptProject
    Private _scriptItems As ScriptItems
    Private _connectionString As String
    Private _enumerator As IEnumerator(Of ScriptItem)
    Private _executionProvider As IExecutionProvider

    ''' <summary>
    ''' Creates a new instance of the ScriptExecutor class.
    ''' </summary>
    ''' <param name="scriptProject">This is the project</param>
    ''' <param name="scripts">This is the list of scripts to execute</param>
    ''' <remarks></remarks>
    Public Sub New(ByVal scriptProject As ScriptProject, _
                   ByVal scripts As IEnumerable(Of Script), _
                   ByVal connectionString As String)

        If scriptProject Is Nothing Then Throw New ArgumentNullException("scriptProject")
        If scripts Is Nothing Then Throw New ArgumentNullException("scripts")
        If String.IsNullOrEmpty(connectionString) Then Throw New ArgumentException("connectionString is empty or null", "connectionString")

        'Save the project
        _scriptProject = scriptProject

        'Save the connection string(just in case)
        _connectionString = connectionString

        _scriptItems = New ScriptItems()

        For Each script As Script In scripts

            Try

                'Add the script items from each 
                _scriptItems.AddRange(script.GetScriptItems(scriptProject.Options.BaseDirectory))

            Catch ex As Exception
                'Let's throw a specific exception so that the UI can go to the script in question.
                Throw New ScriptLoadException(script, ex)
            End Try

        Next

        'TODO: Replace this with code which selects the correct type of execution context
        _executionProvider = New SqlServer.SqlExecutionProvider()

        'Iniialize the execution context
        _executionProvider.Initialize(scriptProject, connectionString)

        'Get an enumerator for the list of scripts
        _enumerator = _scriptItems.GetEnumerator()

        'Move to the first 
        _enumerator.MoveNext()

    End Sub

    Public ReadOnly Property Current() As ScriptItem
        Get
            'Make sure we're not disposed
            CheckDisposed()

            'Return the current item
            Return _enumerator.Current
        End Get
    End Property

    ''' <summary>
    ''' Executes the next script in the list
    ''' </summary>
    ''' <returns></returns>
    Public Function Execute() As ScriptExecutionResult

        'Make sure we're not disposed
        CheckDisposed()

        'Get the current script item
        Dim scriptItem As ScriptItem = _enumerator.Current

        'Move to the next
        _enumerator.MoveNext()

        'Execute the script item
        Return _executionProvider.Execute(scriptItem)

    End Function

#Region " IDisposable Support "
    ''' <summary>
    ''' Checks to see if this object is already disposed
    ''' </summary>
    ''' <remarks></remarks>
    Private Sub CheckDisposed()
        If _isDisposed Then
            Throw New ObjectDisposedException("ScriptExecutor")
        End If
    End Sub

    ''' <summary>
    ''' To detect redundant calls
    ''' </summary>
    ''' <remarks></remarks>
    Private _isDisposed As Boolean = False

    Public Sub Dispose() Implements IDisposable.Dispose

        'Check to see if we've already done this
        If Not _isDisposed Then

            'Check to see if there is an enumerator (there should be)
            If _enumerator IsNot Nothing Then

                'There was, dispose of it
                _enumerator.Dispose()

                'Ditch the reference while we're at it
                _enumerator = Nothing

            End If

            'Check tsee if there is an exectionProvider (there should be)
            If Not _executionProvider Is Nothing Then

                'Dipose of it
                _executionProvider.Dispose()

                'Ditch the reference
                _executionProvider = Nothing

            End If

            'We might as well get rid of this explicitly too
            _scriptItems = Nothing

            'We don't need to finalize this now
            GC.SuppressFinalize(Me)

            _isDisposed = True
        End If
    End Sub

    Protected Overrides Sub Finalize()
        Me.Dispose()
    End Sub
#End Region

End Class
